﻿using System.Collections.Generic;
using NHibernate;
using NHibernate.Criterion;
using TestBat.IModels.Domain;
using TestBat.IModels.Repositories;

namespace TestBat.Models.Repositories
{
    public abstract class Repository<O, ID> : IRepository<O, ID> where O : class, IDomainEntity
    {
        public Repository(ISessionFactory sessionFactory)
        {
            this.sessionFactory = sessionFactory;
        }

        protected ISession Session { get { return sessionFactory.GetCurrentSession(); } }

        public virtual void MakePersistent(O o)
        {
            Session.SaveOrUpdate(o);
        }

        public void MakeTransient(O o)
        {
            Session.Delete(o);
        }

        public virtual void Refresh(O o)
        {
            if (Session.Contains(o))
            { // entity is part of this session
                var id = Session.GetIdentifier(o);
                Session.Evict(o);
                Session.Load(o, id);
            }
            else
            { // entity is not part of this session
                try
                {
                    Session.Refresh(o); // try, if entity is detached
                }
                catch (UnresolvableObjectException)
                { // object is transient anyway
                    return;
                }
            }
        }

        public IList<O> GetAll()
        {
            return Session.CreateCriteria<O>().List<O>();
        }

        public IList<O> GetAllOrderedBy(string column, bool ascending)
        {
            return Session.CreateCriteria<O>().AddOrder(new Order(column, ascending)).List<O>();
        }

        public IList<T> GetByCriteria<T>(DetachedCriteria criteria) where T : class, O
        {
            return criteria.GetExecutableCriteria(Session).List<T>();
        }

        public abstract O GetByID(ID ID);

        public IList<T> GetBySubtype<T>() where T : class, O
        {
            return Session.CreateCriteria<T>().List<T>();
        }

        public IList<O> GetBySQL(string sql)
        {
            return Session.CreateQuery(sql).List<O>();
        }

        protected ISessionFactory sessionFactory;
    }
}
